#include "types.h"
#include <stdarg.h>


void uart_putc(char c);
void cons_putc(int c);

static char digits[] = "0123456789abcdef";

static int printf_lock = 0;

void acquire_printf_lock(void) {
    while (__sync_lock_test_and_set(&printf_lock, 1)) {}
}

void release_printf_lock(void) {
    __sync_lock_release(&printf_lock);
}

static void
printint(long long xx, int base, int sign)
{
  char buf[20];
  int i;
  unsigned long long x;

  if(sign && (sign = (xx < 0)))
    x = -xx;
  else
    x = xx;

  i = 0;
  do {
    buf[i++] = digits[x % base];
  } while((x /= base) != 0);

  if(sign)
    buf[i++] = '-';

  while(--i >= 0)
    cons_putc(buf[i]);
}

static void
printptr(uint64 x)
{
  int i;
  cons_putc('0');
  cons_putc('x');
  for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
    cons_putc(digits[x >> (sizeof(uint64) * 8 - 4)]);
}

int
printf(char *fmt, ...)
{
  va_list ap;
  int i, cx, c0, c1, c2;
  char *s;

  acquire_printf_lock();

  va_start(ap, fmt);
  for(i = 0; (cx = fmt[i] & 0xff) != 0; i++){
    if(cx != '%'){
      cons_putc(cx);
      continue;
    }
    i++;
    c0 = fmt[i+0] & 0xff;
    c1 = c2 = 0;
    if(c0) c1 = fmt[i+1] & 0xff;
    if(c1) c2 = fmt[i+2] & 0xff;
    if(c0 == 'd'){
      printint(va_arg(ap, int), 10, 1);
    } else if(c0 == 'l' && c1 == 'd'){
      printint(va_arg(ap, uint64), 10, 1);
      i += 1;
    } else if(c0 == 'l' && c1 == 'l' && c2 == 'd'){
      printint(va_arg(ap, uint64), 10, 1);
      i += 2;
    } else if(c0 == 'u'){
      printint(va_arg(ap, uint32), 10, 0);
    } else if(c0 == 'l' && c1 == 'u'){
      printint(va_arg(ap, uint64), 10, 0);
      i += 1;
    } else if(c0 == 'l' && c1 == 'l' && c2 == 'u'){
      printint(va_arg(ap, uint64), 10, 0);
      i += 2;
    } else if(c0 == 'x'){
      printint(va_arg(ap, uint32), 16, 0);
    } else if(c0 == 'l' && c1 == 'x'){
      printint(va_arg(ap, uint64), 16, 0);
      i += 1;
    } else if(c0 == 'l' && c1 == 'l' && c2 == 'x'){
      printint(va_arg(ap, uint64), 16, 0);
      i += 2;
    } else if(c0 == 'p'){
      printptr(va_arg(ap, uint64));
    } else if(c0 == 'c'){
      cons_putc(va_arg(ap, uint));
    } else if(c0 == 's'){
      if((s = va_arg(ap, char*)) == 0)
        s = "(null)";
      for(; *s; s++)
        cons_putc(*s);
    } else if(c0 == '%'){
      cons_putc('%');
    } else if(c0 == 0){
      break;
    } else {
      cons_putc('%');
      cons_putc(c0);
    }
  }
  va_end(ap);

  release_printf_lock();
  return 0;
}

void printf_init(void) {
    printf_lock = 0;
}

// 清屏函数
void clear_screen(void) {
     printf("\33[2J");
     printf("\33[H");
}

void test_printf_basic() {
    printf("Testing printf\n");
    printf("Testing integer: %d\n", 42);
    printf("Testing negative: %d\n", -123);
    printf("Testing zero: %d\n", 0);
    printf("Testing hex: 0x%x\n", 0xABC);
    printf("Testing string: %s\n", "Hello");
    printf("Testing char: %c\n", 'X');
    printf("Testing percent: %%\n");
}
 
void test_printf_edge_cases() {
    printf("INT_MAX: %d\n", 2147483647);
    printf("INT_MIN: %d\n", -2147483648);
    printf("INT_MIN: %d\n", -2147483648);
    printf("NULL string: %s\n", (char*)0);
    printf("Empty string: %s\n", "");
}

void test_clear_screen(){
    printf("Testing clear screen ...\n");
    for (volatile int i = 0; i < 50000000; i++);
    clear_screen();
    for (volatile int i = 0; i < 50000000; i++);
    printf("Screen cleared!\n");
}